package org.jma.app.ewisdom.services;

import java.util.HashMap;
import java.util.Vector;

import org.jma.app.ewisdom.entities.Content;
import org.jma.app.ewisdom.entities.ContentsVector;
import org.jma.app.ewisdom.entities.User;
import org.jma.app.ewisdom.exceptions.ContentException;
import org.jma.app.ewisdom.exceptions.GroupException;
import org.jma.app.ewisdom.exceptions.UserException;
import org.jma.lib.soap.SOAPProxy;
import org.jma.lib.soap.sessions.SOAPSession;

import easypastry.core.PastryKernel;
import easypastry.dht.DHTException;
import easypastry.dht.DHTHandler;
import easypastry.util.Utilities;

/**
 * SrvContentManager class allows the access to the Indexes, indexes are trees of content nodes. It publishes
 * as services described below.<br>
 * @author Jesus Mari, jesmari@ono.com
 * @version 1.0
 * @since 1.0
 */
public class SrvContentManager {
;
	
	/**
	 * checks if the entity Content has the pair (userName,role) if not, it will throw a ContentException
	 * @param userName
	 * @param content
	 * @param role
	 * @throws ContentException
	 * @throws UserException
	 */
	private void checkRoules(String userName,Content content,String role) throws ContentException, UserException{
		if (content==null) return;
		SrvUserManager sum = new SrvUserManager();
		HashMap soapParams= new HashMap();
		soapParams.put("userName", userName);
		User userObject=  sum.getUserByUserName(soapParams);
		Vector groups = userObject.getGroups();
		boolean authorized = false;
		
		
		if (content.isInACL(userName,role)){
		}else{
			if (groups==null) throw new ContentException("Insufficient privileges");				
			for (int i =0;i<groups.size();i++){
				if (content.isInACL((String)groups.get(i),"CHANGE_CONTENT_ROULES")){
					authorized = true;
					break;
				}
			}
			if (!authorized) throw new ContentException("Insufficient privileges");
		}
	
	}
	
	/**
	 * adds an access roule to a given content
	 * @param soapParams parameters must be a <code>CID</code>  content id, a <code>userName</code> and a <code>role</code>
	 * @return a modified Content 
	 * @throws GroupException
	 * @throws NumberFormatException
	 * @throws ContentException
	 * @throws UserException
	 */
	public Content addContentRoule (HashMap soapParams) throws GroupException, NumberFormatException, ContentException, UserException {

		try{
			String userName = ((SOAPSession)soapParams.get(SOAPProxy.SOAPSession)).getUserName();
			DHTHandler 	dhtContents = PastryKernel.getDHTHandler(Utilities.generateStringHash("p2p://org.jma.app.ewisdom.contents"));

			Content content= (Content)dhtContents.get(((String)soapParams.get("CID")));
			checkRoules(userName,content,"CHANGE_CONTENT_ROULES");
		
			content.addEntityToACL(
					(String)soapParams.get("user"),
					(String)soapParams.get("role"));
				
	
			dhtContents.put(content.getStringHashCode(),content);
			return content;
		} catch (DHTException e) {
			throw new GroupException(e.getMessage());
		}
	}
	
	/**
	 * adds a new content
	 * @param soapParams parameters must be a <code>CID</code>  content id of its parent or <code>"null"</code>, 
	 * a <code>title</code>, the position <code>pos</code>, a comment <code>comment</code>
	 * @return a new Content
	 * @throws GroupException
	 * @throws NumberFormatException
	 * @throws ContentException
	 * @throws UserException
	 */
	public Content addContent (HashMap soapParams) throws GroupException, NumberFormatException, ContentException, UserException {

		try {
			String userName = ((SOAPSession)soapParams.get(SOAPProxy.SOAPSession)).getUserName();
			DHTHandler 	dhtContents = PastryKernel.getDHTHandler(Utilities.generateStringHash("p2p://org.jma.app.ewisdom.contents"));

			Content parent= (Content)dhtContents.get(((String)soapParams.get("parent")));
			
			checkRoules(userName,parent,"ADD_CONTENTS");

			Content newBranch;
			if (parent!=null){
			 	newBranch= parent.addContentsBranch(
								Integer.parseInt((String)soapParams.get("pos")),
								(String)soapParams.get("title"),
								userName);
				newBranch.setACL(parent.getACLClone());
				newBranch.setComment((String)soapParams.get("comment"));
				dhtContents.put(parent.getStringHashCode(), parent);
			} else {
				//parent ==null
				newBranch= new Content((String)soapParams.get("title"),"null");
				newBranch.addEntityToACL(userName, "ADD_CONTENTS");
				newBranch.addEntityToACL(userName, "READ_CONTENTS");
				newBranch.addEntityToACL(userName, "REMOVE_CONTENTS");
				newBranch.addEntityToACL(userName, "CHANGE_CONTENT_ROULES");
				newBranch.setComment((String)soapParams.get("comment"));	
				//we have to save the first content of each index.
				addToContentsIndex(newBranch);
				
			}
			dhtContents.put(newBranch.getStringHashCode(),newBranch);
			
			return newBranch;
		} catch (Exception e) {
			throw new ContentException(e.getMessage());
		}
	}
	
	
	/**
	 * removes a content
	 * @param soapParams an identification <code>CID<code>.
	 * @return the removed Content
	 * @throws ContentException
	 * @throws GroupException
	 * @throws UserException
	 */
	public Content removeContent (HashMap soapParams) throws ContentException, GroupException, UserException {
		try {
			String userName = ((SOAPSession)soapParams.get(SOAPProxy.SOAPSession)).getUserName();
			DHTHandler 	dhtContents = PastryKernel.getDHTHandler(Utilities.generateStringHash("p2p://org.jma.app.ewisdom.contents"));

			Content content= (Content)dhtContents.get((String)soapParams.get("CID"));
		
			checkRoules(userName,content,"REMOVE_CONTENTS");
			
			if (content.getParent()==null) removeFromContentsIndex(content);
			recursiveRemove((String)soapParams.get("CID"));			
			return content;
		} catch (DHTException e) {
			throw new ContentException(e.getMessage());
		} catch (CloneNotSupportedException e) {
			throw new ContentException(e.getMessage());
		}
	}
	
	/**
	 * returns all the root Contents.
	 * @param there are no parameters.
	 * @return a ContentVector
	 * @throws ContentException
	 */
	public ContentsVector getIndexes(HashMap soapParams) throws ContentException{
		try{
			DHTHandler 	dhtContents = PastryKernel.getDHTHandler(Utilities.generateStringHash("p2p://org.jma.app.ewisdom.contents"));

			ContentsVector cv =(ContentsVector)dhtContents.get("contents.Vector");
			if (cv==null) return new ContentsVector();
			else return cv;
		} catch (DHTException e) {
			throw new ContentException(e.getMessage());
		}
	}
	
	/**
	 * 
	 * @param soapParams a Content identification <code>CID</code>
	 * @return a Content
	 * @throws ContentException
	 * @throws UserException
	 * @throws DHTException
	 */
	public Content getContent(HashMap soapParams) throws ContentException, UserException, DHTException{
		String userName = ((SOAPSession)soapParams.get(SOAPProxy.SOAPSession)).getUserName();
		DHTHandler 	dhtContents = PastryKernel.getDHTHandler(Utilities.generateStringHash("p2p://org.jma.app.ewisdom.contents"));

		Content content= (Content)dhtContents.get((String)soapParams.get("CID"));
	
		checkRoules(userName,content,"READ_CONTENTS");
		return content;
	}

	/**
	 * Inter-classes method, it allows to update a content,  its not a soap service
	 * @param content an updated content
	 * @throws DHTException
	 */
	public void updateContent(Content content) throws  DHTException{
		DHTHandler 	dhtContents = PastryKernel.getDHTHandler(Utilities.generateStringHash("p2p://org.jma.app.ewisdom.contents"));

		dhtContents.put(content.getStringHashCode(),content);
		
	}
	
	/**
	 * Inter-classes method, it allows to update a content,  it's not a soap service
	 * @param content a new content
	 * @throws DHTException
	 */
	
	private void recursiveRemove(String content) throws DHTException{
		DHTHandler 	dhtContents = PastryKernel.getDHTHandler(Utilities.generateStringHash("p2p://org.jma.app.ewisdom.contents"));

		Content removedBranch = (Content) dhtContents.get(content);
		for ( int i=0; i<removedBranch.getNumberOfBranches();i++){
			recursiveRemove(removedBranch.getContentsBranch(i));
		}
		dhtContents.remove(content);
	}
	
	/**
	 * Adds a root content to the contents vector (initial contents), it's not a soap service
	 * @param content a content with the parent CID set to "null"
	 * @throws CloneNotSupportedException
	 * @throws ContentException
	 */
	protected void addToContentsIndex(Content content) throws CloneNotSupportedException, ContentException{
		try {
			DHTHandler 	dhtContents = PastryKernel.getDHTHandler(Utilities.generateStringHash("p2p://org.jma.app.ewisdom.contents"));

			ContentsVector set = (ContentsVector) dhtContents.get("contents.Vector");
		
			if (set == null) {
				set = new ContentsVector();
			}			
			set.add((Content)content.clone());
			dhtContents.put("contents.Vector", set);
		} catch (DHTException e) {
			throw new ContentException(e.getMessage());
		}
	}
	/**
	 * Removes a root content from the contents vector (initial contents), it's not a soap service
	 * @param content a content with the parent CID set to "null"
	 * @throws CloneNotSupportedException
	 * @throws ContentException
	 */
	protected void removeFromContentsIndex(Content content) throws CloneNotSupportedException, ContentException{
		try {
			DHTHandler 	dhtContents = PastryKernel.getDHTHandler(Utilities.generateStringHash("p2p://org.jma.app.ewisdom.contents"));

			ContentsVector set = (ContentsVector) dhtContents.get("contents.Vector");
		
			if (set == null) {
				set = new ContentsVector();
			}			
			set.remove(content);
			dhtContents.put("contents.Vector", set);
		} catch (DHTException e) {
			throw new ContentException(e.getMessage());
		}
	}
}
